using System.Collections.Generic;
using System.Linq;

namespace Commons.Utils
{
	public class SortedMultiMap<K, V>
	{
		private SortedDictionary<K, List<V>> dictionary = new SortedDictionary<K, List<V>>();

		public int Count
		{
			get
			{
				return dictionary.Count;
			}
		}

		public int TotalCount
		{
			get
			{
				int count = 0;
				foreach (List<V> values in dictionary.Values)
				{
					count += values.Count;
				}
				return count;
			}
		}

		public IEnumerable<K> Keys
		{
			get
			{
				return dictionary.Keys;
			}
		}

		public IEnumerable<V> Values
		{
			get
			{
				foreach (List<V> values in dictionary.Values)
				{
					foreach (V value in values)
					{
						yield return value;
					}
				}
			}
		}

		public K FirstKey
		{
			get
			{
				return dictionary.First().Key;
			}
		}

		public K LastKey
		{
			get
			{
				return dictionary.Last().Key;
			}
		}

		private K GetKey(int index)
		{
			return index >= 0 && index < dictionary.Count ? dictionary.ElementAt(index).Key : default(K);
		}

		public bool ContainsKey(K key)
		{
			return dictionary.ContainsKey(key);
		}

		public List<V> Get(K key)
		{
			List<V> values;

			return dictionary.TryGetValue(key, out values) ? values : null;
		}

		public void Add(K key, V value)
		{
			List<V> values;
			if (!dictionary.TryGetValue(key, out values))
			{
				values = dictionary[key] = new List<V>();
			}
			values.Add(value);
		}

		public void Move(K fromKey, K toKey)
		{
			List<V> fromValues;
			if (dictionary.TryGetValue(fromKey, out fromValues))
			{
				dictionary.Remove(fromKey);

				List<V> toValues;
				if (dictionary.TryGetValue(toKey, out toValues))
				{
					toValues.AddRange(fromValues);
				}
				else
				{
					dictionary.Add(toKey, fromValues);
				}
			}
		}

		public bool Remove(K key)
		{
			return dictionary.Remove(key);
		}

		public void RemoveRange(K key, int index, int count)
		{
			List<V> values;
			if (dictionary.TryGetValue(key, out values))
			{
				values.RemoveRange(index, count);

				if (values.Count == 0)
				{
					dictionary.Remove(key);
				}
			}
		}

		public void Clear()
		{
			dictionary.Clear();
		}
	}
}

